﻿using Common;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace MongoDB
{
    /// <summary>
    /// MongoDB驱动类
    /// </summary>
    public class MongoDBDrive : IMongoDB
    {
        private readonly string connectionString = ConfigHelper.Configuration["MongoDBCondition"];
        private readonly string MongoDBName = ConfigHelper.Configuration["MongoDBDataBase"];
        private readonly IMongoClient client;
        private readonly IMongoDatabase DB;
        public MongoDBDrive()
        {
            client = new MongoClient(connectionString);//连接MongoDB
            DB = client.GetDatabase(MongoDBName);//加载MongoDB库
        }

        /// <summary>
        /// 获取MongoDB数据库
        /// </summary>
        /// <param name="DatabaseName"></param>
        /// <returns></returns>
        public IMongoDatabase GetMongoDatabase(string DatabaseName)
        {
            return client.GetDatabase(DatabaseName);
        }

        /// <summary>
        /// 获取MongoDB集合(类似于表)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="CollectionName"></param>
        /// <returns></returns>
        public IMongoCollection<T> GetCollection<T>(string DatabaseName, string CollectionName)
        {
            return client.GetDatabase(DatabaseName).GetCollection<T>(CollectionName);
        }

        /// <summary>
        /// 获取MongoDB集合(类似于表)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="CollectionName"></param>
        /// <returns></returns>
        public IMongoCollection<T> GetCollection<T>(string CollectionName)
        {
            return DB.GetCollection<T>(CollectionName);
        }

        /// <summary>
        /// 删除集合（表）
        /// </summary>
        /// <param name="CollectionName"></param>
        public void DropCollection(string CollectionName)
        {
            DB.DropCollection(CollectionName);
        }

        /// <summary>
        /// 删除集合（表）
        /// </summary>
        /// <param name="CollectionName"></param>
        public void DropCollection(string DatabaseName, string CollectionName)
        {
            client.GetDatabase(DatabaseName).DropCollection(CollectionName);
        }

        /// <summary>
        /// 删除集合（表）
        /// </summary>
        /// <param name="CollectionName"></param>
        public async Task DropCollectionAsync(string CollectionName)
        {
            await DB.DropCollectionAsync(CollectionName).ConfigureAwait(false);
        }

        /// <summary>
        /// 删除集合（表）
        /// </summary>
        /// <param name="CollectionName"></param>
        public async Task DropCollectionAsync(string DatabaseName, string CollectionName)
        {
            await client.GetDatabase(DatabaseName).DropCollectionAsync(CollectionName).ConfigureAwait(false);
        }
    }

    /// <summary>
    /// MongoDB拓展类
    /// </summary>
    public static class MongoDBExpand
    {
        /// <summary>
        /// 查询数据,并且返回第一条数据，如果没有查询出来则为空
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <returns></returns>
        public static T FindInfo<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where)
        {
            return Collection.Find(Where).FirstOrDefault();
        }

        /// <summary>
        /// 查询数据,并且返回第一条数据，如果没有查询出来则为空(异步)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <returns></returns>
        public static async Task<T> FindInfoAsync<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where)
        {
            return await Collection.Find(Where).FirstOrDefaultAsync().ConfigureAwait(false);
        }

        /// <summary>
        /// 查询数据,返回列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <param name="order"></param>
        /// <param name="orderType"></param>
        /// <returns></returns>
        public static List<T> FindList<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where, Expression<Func<T, object>> order = null, string orderType = "asc")
        {
            var list = Collection.Find(Where);
            if (order != null)
            {
                if (orderType != "desc")
                {
                    if (orderType != "desc")
                    {
                        list = list.SortBy(order);
                    }
                    else
                    {
                        list = list.SortByDescending(order);
                    }
                }
            }
            return list.ToList();
        }

        /// <summary>
        /// 查询数据,返回列表(异步)
        /// </summary>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <param name="order"></param>
        /// <param name="orderType"></param>
        /// <returns></returns>
        public static async Task<List<T>> FindListAsync<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where, Expression<Func<T, object>> order = null, string orderType = "asc")
        {
            var list = Collection.Find(Where);
            if (order != null)
            {
                if (orderType != "desc")
                {
                    if (orderType != "desc")
                    {
                        list = list.SortBy(order);
                    }
                    else
                    {
                        list = list.SortByDescending(order);
                    }
                }
            }
            return await list.ToListAsync().ConfigureAwait(false);
        }
        /// <summary>
        /// 获取MongoDB分页数据集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <param name="limit"></param>
        /// <param name="page"></param>
        /// <returns></returns>
        public static PageModel<T> FindPageList<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where, Expression<Func<T, object>> order = null, string orderType = "asc", int limit = 10, int page = 1)
        {
            var FindFluent = Collection.Find(Where);
            var Count = FindFluent.CountDocuments();
            var PageCount = Count / limit;
            var list = FindFluent.Limit(limit).Skip((page - 1) * limit);
            var result = new List<T>();
            if (order != null)
            {
                if (orderType != "desc")
                {
                    list = list.SortBy(order);
                }
                else
                {
                    list = list.SortByDescending(order);
                }
            }
            return new PageModel<T>()
            {
                count = (int)Count,
                PageCount = (int)PageCount,
                PageIndex = page,
                PageSize = limit,
                data = list.ToList(),
                code = Count == 0 ? -1 : 0,
                msg = Count == 0 ? "未找到数据" : string.Empty
            };
        }

        /// <summary>
        /// 获取MongoDB分页数据集合(异步)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="Where"></param>
        /// <param name="limit"></param>
        /// <param name="page"></param>
        /// <returns></returns>
        public static async Task<PageModel<T>> FindPageListAsync<T>(this IMongoCollection<T> Collection, Expression<Func<T, bool>> Where, Expression<Func<T, object>> order = null, string orderType = "asc", int limit = 10, int page = 1)
        {
            var FindFluent = Collection.Find(Where);
            var Count = FindFluent.CountDocuments();
            var PageCount = Count / limit;
            var list = FindFluent.Limit(limit).Skip((page - 1) * limit);
            var result = new List<T>();
            if (order != null)
            {
                if (orderType != "desc")
                {
                    list = list.SortBy(order);
                }
                else
                {
                    list = list.SortByDescending(order);
                }
            }
            return new PageModel<T>()
            {
                count = (int)Count,
                PageCount = (int)PageCount,
                PageIndex = page,
                PageSize = limit,
                data = await list.ToListAsync(),
                code = Count == 0 ? -1 : 0,
                msg = Count == 0 ? "未找到数据":string.Empty
            };
        }

        /// <summary>
        /// MongoDB修改数据
        /// </summary>
        /// <returns></returns>
        public static UpdateResult Update<T>(this IMongoCollection<T> Collection, object Data, object where)
        {
            List<FilterDefinition<T>> filters = new List<FilterDefinition<T>>();
            foreach (var item in where.GetType().GetProperties())
            {
                filters.Add(Builders<T>.Filter.Eq(item.Name, item.GetValue(where)));
            }
            //修改条件
            FilterDefinition<T> filter = Builders<T>.Filter.And(filters.ToArray());
            //要修改的字段
            var list = new List<UpdateDefinition<T>>();
            foreach (var item in Data.GetType().GetProperties())
            {
                if (item.Name.ToLower() == "id") continue;
                list.Add(Builders<T>.Update.Set(item.Name, item.GetValue(Data)));
            }
            var updatefilter = Builders<T>.Update.Combine(list);
            return Collection.UpdateMany(filter, updatefilter);
        }

        /// <summary>
        /// MongoDB修改数据(异步)
        /// </summary>
        /// <returns></returns>
        public static async Task<UpdateResult> UpdateAsync<T>(this IMongoCollection<T> Collection, object Data, object where)
        {
            List<FilterDefinition<T>> filters = new List<FilterDefinition<T>>();
            foreach (var item in where.GetType().GetProperties())
            {
                filters.Add(Builders<T>.Filter.Eq(item.Name, item.GetValue(where)));
            }
            //修改条件
            FilterDefinition<T> filter = Builders<T>.Filter.And(filters.ToArray());
            //要修改的字段
            var list = new List<UpdateDefinition<T>>();
            foreach (var item in Data.GetType().GetProperties())
            {
                if (item.Name.ToLower() == "id") continue;
                list.Add(Builders<T>.Update.Set(item.Name, item.GetValue(Data)));
            }
            var updatefilter = Builders<T>.Update.Combine(list);
            return await Collection.UpdateManyAsync(filter, updatefilter).ConfigureAwait(false);
        }

        /// <summary>
        /// 删除MongoDB数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static DeleteResult Delete<T>(this IMongoCollection<T> Collection, object where)
        {
            List<FilterDefinition<T>> filters = new List<FilterDefinition<T>>();
            foreach (var item in where.GetType().GetProperties())
            {
                filters.Add(Builders<T>.Filter.Eq(item.Name, item.GetValue(where)));
            }
            //修改条件
            FilterDefinition<T> filter = Builders<T>.Filter.And(filters.ToArray());
            return Collection.DeleteMany(filter);
        }

        /// <summary>
        /// 删除MongoDB数据(异步)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Collection"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static async Task<DeleteResult> DeleteAsync<T>(this IMongoCollection<T> Collection, object where)
        {
            List<FilterDefinition<T>> filters = new List<FilterDefinition<T>>();
            foreach (var item in where.GetType().GetProperties())
            {
                filters.Add(Builders<T>.Filter.Eq(item.Name, item.GetValue(where)));
            }
            //修改条件
            FilterDefinition<T> filter = Builders<T>.Filter.And(filters.ToArray());
            return await Collection.DeleteManyAsync(filter).ConfigureAwait(false);
        }


    }
}
